package jsu.blogger.service.impl;
import jsu.blogger.config.RedisKeyPrefixConfig;
import jsu.blogger.mapper.CollectMapper;
import jsu.blogger.mapper.PostLikeMapper;
import jsu.blogger.mapper.PostMapper;
import jsu.blogger.pojo.BlogPostDetails;
import jsu.blogger.pojo.Post;
import jsu.blogger.pojo.UserFolder;
import jsu.blogger.service.AdvancedRedisService;
import jsu.blogger.service.inter.PostService;
import jsu.blogger.util.FileUtil;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class PostServiceImpl implements PostService {
    private static final Logger logger = LoggerFactory.getLogger(PostServiceImpl.class);
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private PostMapper postMapper;
    @Autowired
    private AdvancedRedisService advancedRedisService;
    @Autowired
    private RedissonClient redissonClient;

    @Autowired
   private PostLikeMapper postLikeMapper;

    /**
     * 执行 Lua 脚本，确保只有在 likesCount > 0 或 dislikeCount > 0 时递减，若不成功则删除 Redis 键
     *
     * @param postId 帖子ID
     * @param isLike true: 递减 likesCount，false: 递减 dislikeCount
     * @return true 如果操作成功 (likesCount 或 dislikeCount > 0)，false 如果操作失败 (count <= 0，且键被删除)
     */
    public boolean decrementLikeOrDislikeCountAndHandleRedis(Long postId, boolean isLike) {
        // 构建 Redis 键
        String blogKey = RedisKeyPrefixConfig.BLOG_HASH_KEY_PREFIX + postId;

        try {
            // Lua 脚本：确保只有在 likesCount > 0 或 dislikeCount > 0 时才递减，若不成功则删除 Redis 键
            String luaScript = isLike ?
                    "local likesCount = tonumber(redis.call('HGET', KEYS[1], 'likesCount')) " +
                            "if likesCount and likesCount > 0 then " +
                            "    redis.call('HINCRBY', KEYS[1], 'likesCount', -1) " +
                            "    return likesCount - 1 " +
                            "else " +
                            "    redis.call('DEL', KEYS[1]) " +
                            "    return 'likesCount is already 0, and key deleted' " +  // 返回字符串
                            "end" :
                    "local dislikeCount = tonumber(redis.call('HGET', KEYS[1], 'dislikeCount')) " +
                            "if dislikeCount and dislikeCount > 0 then " +
                            "    redis.call('HINCRBY', KEYS[1], 'dislikeCount', -1) " +
                            "    return dislikeCount - 1 " +
                            "else " +
                            "    redis.call('DEL', KEYS[1]) " +
                            "    return 'dislikeCount is already 0, and key deleted' " +  // 返回字符串
                            "end";
            // 执行 Lua 脚本
            List<Object> resultList = redisTemplate.execute(
                    new DefaultRedisScript<>(luaScript, List.class),
                    Collections.singletonList(blogKey)
            );
            // 检查返回结果
            if (resultList != null && !resultList.isEmpty()) {
                // 处理返回的结果
                Object result = resultList.get(0);
                if (result instanceof Map resultMap) {
                    // 如果返回的是错误信息，表示操作失败
                    if (resultMap.containsKey("err")) {
                        logger.error("Redis 错误: " + resultMap.get("err"));
                        return false; // 返回 false，表示操作失败
                    }
                } else {
                    // 如果返回的是数字，表示成功，返回 true
                    return true;
                }
            }
            return  true;
        }catch (Exception e) {
           throw new RuntimeException("取消点赞和踩的脚本执行异常");
        }
    }

    /**
     * 执行 Lua 脚本，确保只有在 likesCount > 0 时递减，若不成功则删除 Redis 键
     *  不喜欢增加 喜欢减少
     * @param postId 帖子ID
     * @return 返回包含操作结果的 List 对象
     */
    public List<Object> updateLikeDislikeCountDecrementLike(Long postId) {
        // 构建 Redis 键
        String blogKey = RedisKeyPrefixConfig.BLOG_HASH_KEY_PREFIX + postId;

        // Lua 脚本：确保只有在 likesCount > 0 时递减，若不成功则删除 Redis 键
        String luaScript =
                "local likesCount = tonumber(redis.call('HGET', KEYS[1], 'likesCount')) " +
                        "local dislikeCount = tonumber(redis.call('HGET', KEYS[1], 'dislikeCount')) " +
                        "if likesCount > 0 then " +  // 如果喜欢数大于 0
                        "    redis.call('HINCRBY', KEYS[1], 'likesCount', -1) " +  // 减少喜欢数
                        "else " +
                        "    redis.call('DEL', KEYS[1]) " +  // 如果喜欢数为 0，删除 Redis 键
                        "    return {err='likesCount is already 0, and key deleted'} " +  // 返回错误信息
                        "end " +
                        "redis.call('HINCRBY', KEYS[1], 'dislikeCount', 1) " +  // 增加不喜欢数
                        "return {likesCount - 1, dislikeCount + 1}";

        // 执行 Lua 脚本
        return redisTemplate.execute(
                new DefaultRedisScript<>(luaScript, List.class),
                Collections.singletonList(blogKey)
        );
    }

    /**
     * 执行 Lua 脚本，确保只有在 dislikeCount > 0 时递减，若不成功则删除 Redis 键
     * 不喜欢减少 喜欢增多
     * @param postId 帖子ID
     * @return 返回包含操作结果的 List 对象
     */
    public List<Object> updateLikeDislikeCountDecrementDislike(Long postId) {
        // 构建 Redis 键
        String blogKey = RedisKeyPrefixConfig.BLOG_HASH_KEY_PREFIX + postId;

        // Lua 脚本：确保只有在 dislikeCount > 0 时递减，若不成功则删除 Redis 键
        String luaScript =
                "local dislikeCount = tonumber(redis.call('HGET', KEYS[1], 'dislikeCount')) " +
                        "local likesCount = tonumber(redis.call('HGET', KEYS[1], 'likesCount')) " +
                        "if dislikeCount > 0 then " +  // 如果不喜欢数大于 0
                        "    redis.call('HINCRBY', KEYS[1], 'dislikeCount', -1) " +  // 减少不喜欢数
                        "else " +
                        "    redis.call('DEL', KEYS[1]) " +  // 如果不喜欢数为 0，删除 Redis 键
                        "    return {err='dislikeCount is already 0, and key deleted'} " +  // 返回错误信息
                        "end " +
                        "redis.call('HINCRBY', KEYS[1], 'likesCount', 1) " +  // 增加喜欢数
                        "return {dislikeCount - 1, likesCount + 1}";

        // 执行 Lua 脚本
        return redisTemplate.execute(
                new DefaultRedisScript<>(luaScript, List.class),
                Collections.singletonList(blogKey)
        );
    }

    /**
     * 执行点赞或踩操作
     *
     * @param userId 用户ID
     * @param postId 帖子ID
     * @param isLike 是否点赞（1为点赞，0为踩）
     * @return 操作结果：1（操作成功），0（操作失败）
     */
    @Transactional
    public int handlePostLike(Long userId, Long postId, boolean isLike) {
        // 1. 查询用户对帖子的操作状态
        Integer currentStatus = getUserPostLikeStatus(userId, postId);
        String blogKey = RedisKeyPrefixConfig.BLOG_HASH_KEY_PREFIX + postId;
        HashOperations<String, String, String> hashOps = redisTemplate.opsForHash();
        boolean isNeedRedisOp=Boolean.TRUE.equals(redisTemplate.hasKey(blogKey));
        // 2. 如果没有记录，插入新的点赞/踩记录
        try {
            if (currentStatus == null) {
                int result = postLikeMapper.insertPostLike(userId, postId, isLike);
                if (result > 0) {
                    // 更新 Redis 中的喜欢数和不喜欢数
                    if (isLike) {
                        // 增加喜欢数
                        postMapper.increaseLikesCount(postId);
                        if (isNeedRedisOp) {
                            hashOps.increment(blogKey, "likesCount", 1);
                        }
                    } else {
                        // 增加不喜欢数
                        postMapper.increaseDislikeCount(postId);
                        if (isNeedRedisOp) {
                            hashOps.increment(blogKey, "dislikeCount", 1);
                        }
                    }
                }
                return result;
            } else {
                // 5. 如果已经有记录，检查当前状态，决定是否需要更新
                if ((currentStatus == 1) == isLike) {
                    return 0;  // 操作失败
                } else {
                    // 更新记录
                    int updateResult = postLikeMapper.updatePostLike(userId, postId, isLike);
                    if (updateResult > 0) {
                        // 更新计数
                        if (isLike) {
                            // 如果是点赞，减少不喜欢数，增加喜欢数
                            postMapper.decreaseDislikeCount(postId);
                            postMapper.increaseLikesCount(postId);
                            if (isNeedRedisOp) {
                                updateLikeDislikeCountDecrementDislike(postId);
                            }
                        } else {
                            // 如果是取消点赞，增加不喜欢数，减少喜欢数
                            postMapper.decreaseLikesCount(postId);
                            postMapper.increaseDislikeCount(postId);
                            if (isNeedRedisOp) {
                                updateLikeDislikeCountDecrementLike(postId);
                            }
                        }
                    }
                    return updateResult;
                }
            }
        }catch (Exception e){
            logger.error("处理点赞和踩的业务发送错误"+e);
            //删除博客
            redisTemplate.delete(blogKey);
            throw  e;
        }
    }
    /**
     * 查询并删除用户对帖子的点赞或踩记录
     *
     * @param userId 用户ID
     * @param postId 帖子ID
     * @return 如果删除成功，返回 1；如果没有找到记录，返回 0
     */
    @Transactional
    public int removeUserLikeOrDislike(Long userId, Long postId) {
        // 查询用户对帖子的操作状态
        Integer currentStatus = getUserPostLikeStatus(userId, postId);
       // HashOperations<String, String, String> hashOps = redisTemplate.opsForHash();
        String blogKey = RedisKeyPrefixConfig.BLOG_HASH_KEY_PREFIX + postId;
        boolean isNeedRedisOp=Boolean.TRUE.equals(redisTemplate.hasKey(blogKey));
        logger.info("取消点赞和踩的方法中-----当前点赞状态: "+currentStatus  +", 是否需要数据库操作: "+isNeedRedisOp);
        try {
            // 如果当前状态是点赞或踩，则删除记录
            if (currentStatus != null) {
                int result = postLikeMapper.deletePostLike(userId, postId);
                logger.info("取消点赞和踩的方法中-----点赞记录删除是否成功: "+result);
                if(result>0){
                    if (currentStatus==1) {
                        // 如果是点赞 减少喜欢数
                        postMapper.decreaseLikesCount(postId);
                        if (isNeedRedisOp) {
                            decrementLikeOrDislikeCountAndHandleRedis(postId,true);
                            //hashOps.increment(blogKey, "likesCount", -1);
                        }
                    } else {
                        // 如果是取消踩，减少不喜欢数
                        postMapper.decreaseDislikeCount(postId);
                        if (isNeedRedisOp) {
                            decrementLikeOrDislikeCountAndHandleRedis(postId,false);
                            //hashOps.increment(blogKey, "dislikeCount", -1);
                        }
                    }
                }
                return result;
            } else {
                // 如果没有操作，返回 0
                return 0;
            }
        }catch (Exception e){
            logger.error("取消点赞或踩的业务发送错误"+e);
            //删除博客
            redisTemplate.delete(blogKey);
            throw e;
            //return -1;//操作异常
        }
    }

    //获取用户对博客的点赞情况
    /**
     * 查询用户对帖子的操作状态
     *
     * @param userId 用户ID
     * @param postId 帖子ID
     * @return 返回点赞、踩的状态：1（点赞）、0（踩）、-1（没有操作）
     */
    public Integer getUserPostLikeStatus(Long userId, Long postId) {
        return postLikeMapper.getUserPostLikeStatus(userId, postId);
    }


    //是否增加博客阅读量
    @Transactional
    public boolean incrementReadCount(Long userId,Long postId) {
         HashOperations<String, String, String> hashOps = redisTemplate.opsForHash();
         String hashKey=RedisKeyPrefixConfig.BLOG_HASH_KEY_PREFIX +postId;
        Long currentTimestamp = System.currentTimeMillis() / 1000;
        try {
            if (checkUserRead(userId, postId, currentTimestamp)) {
                int updatedRows = postMapper.incrementReadCount(postId);
                if (updatedRows > 0 && Boolean.TRUE.equals(redisTemplate.hasKey(hashKey))) {
                    hashOps.increment(hashKey, "readCount", 1);
                }
                return updatedRows>0;
            }
        }catch (Exception e){
            logger.error("增加阅读量错误"+e);
            //删除博客
            redisTemplate.delete(hashKey);
            throw e;

        }
        return false;
    }

    //判断是否对此博客阅读量是否有效
    public boolean checkUserRead(Long userId,Long postId, Long currentTimestamp) {
        String key=RedisKeyPrefixConfig.USER_ZSET_POST_READ_KEY_EXPIRE+userId;
        // Lua 脚本
        String script = "local key = KEYS[1] " +
                "local postId = ARGV[1] " +
                "local currentTime = tonumber(ARGV[2]) " +
                "local sevenDaysInSeconds = 7 * 24 * 60 * 60 " +
                "local cutoffTime = currentTime - sevenDaysInSeconds " +
                "local toRemove = {} " +
                "local elements = redis.call('ZRANGEBYSCORE', key, '-inf', cutoffTime) " +
                "for _, element in ipairs(elements) do " +
                "    table.insert(toRemove, element) " +
                "end " +
                "if #toRemove > 0 then " +
                "    redis.call('ZREM', key, unpack(toRemove)) " +
                "end " +
                "local exists = redis.call('ZSCORE', key, postId) " +
                "if exists == false then " +
                "    redis.call('ZADD', key, currentTime, postId) " +
                "    return true " +
                "else " +
                "    return false " +
                "end";

        // 执行 Lua 脚本
        DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>();
        redisScript.setScriptText(script);
        redisScript.setResultType(Boolean.class);

        Boolean result = redisTemplate.execute(redisScript, Collections.singletonList(key), String.valueOf(postId), String.valueOf(currentTimestamp));
        logger.info("result："+String.valueOf(result));

        return result != null && result;



    }


    public List<BlogPostDetails> searchUserAllBlogs(Long userId,Long count,Long offset){
        List<BlogPostDetails> blogPostDetailsList=new ArrayList<>();
        List<Long>blogIds=postMapper.getPostIdsByUserIdWithPagination(userId,offset,count);
        for (Long blogId : blogIds) {
            if (!blogId.equals(-1L)) {
                //开始查询数据
                BlogPostDetails blogPostDetail = advancedRedisService.queryWithHashPassThrough(
                        RedisKeyPrefixConfig.BLOG_HASH_KEY_PREFIX,
                        blogId,
                        BlogPostDetails.class,
                        id -> postMapper.getBlogDetailApartContentById(id), // 使用 id 作为参数
                        RedisKeyPrefixConfig.BLOG_HASH_KEY_EXPIRE,
                        TimeUnit.MINUTES
                );
                if (blogPostDetail != null) {
                    blogPostDetailsList.add(blogPostDetail);
                }
            }
        }
        return blogPostDetailsList;
    }

    public boolean deleteBlog(Long userId, Long postId) {
        int rowAffect=postMapper.deleteBlog(userId, postId);
        boolean boo=rowAffect>0;
        if(boo) {
            try {
                //要求删除草稿的相关文件夹和文件
                FileUtil.deleteDirectory(new File(FileUtil.createDirPath(FileUtil.POST_IMG_DIR_NAME + File.separator + postId)));
                logger.info("删除整个临时文件夹" + postId);
                String dir = FileUtil.resourcePath + File.separator + FileUtil.POST_COVER_DIR_NAME;
                FileUtil.deleteFilesByPartialName(dir,String.valueOf(postId));
                logger.info("删除临时文件： " + dir + ", 前缀名: " + postId);
            } catch (Exception e) {
                logger.error(postId+ "博客相关文件删除失败");
            }
        }
        // 调用 deleteBlog 方法删除博客
        return boo;
    }
    @Autowired
    private CollectMapper collectMapper;
    //收藏的实现   收藏帖子的实现
    @Transactional
    public List<String> handlerPostFolders(Long userId, List<Long> folderIds, Long postId){
        boolean isDeleted=false;
        boolean isIncreased=false;
        List<String> folderNames=new ArrayList<>();
        String blogKey = RedisKeyPrefixConfig.BLOG_HASH_KEY_PREFIX + postId;
         HashOperations<String, String, String> hashOps = redisTemplate.opsForHash();
        //删除用户收藏夹中所有的帖子id
       int affect= collectMapper.deletePostFromUserFolders(userId, postId);
       isDeleted=affect>0;//删除成功
        for (Long folderId : folderIds) {
           //遍历收藏夹id 向文件夹插入帖子
            int checked=collectMapper.checkUserFolder(folderId,userId);

            if(checked>0){
                isDeleted=false;
                isIncreased=true;
                collectMapper.insertFolderPost(folderId,postId);
                //根据收藏夹id查询文件夹名
                folderNames.add(collectMapper.getFolderNameById(folderId));
            }else{
                throw new RuntimeException("检查当中的文件夹数据异常");
            }
        }
        if(isDeleted){
            //删除成功
            postMapper.decrementFavoriteCount(postId);
            hashOps.increment(blogKey, "favoriteCount", -1);
        }
        if(affect==0&&isIncreased){
            postMapper.incrementFavoriteCount(postId);
            hashOps.increment(blogKey, "favoriteCount", 1);
        }
        return folderNames;
    }

    //获取默认收藏夹
    public UserFolder getDefaultUserFolder(Long userId){
        try {
            UserFolder userFolder;
            userFolder=collectMapper.getDefaultFolderByUserId(userId);
            if(userFolder==null){
                userFolder=new UserFolder();
                //自动为用户创建默认收藏夹
                userFolder.setUserId(userId);
                userFolder.setFolderDesc("我的默认文件夹");
                userFolder.setFolderName("默认文件夹");
                userFolder.setVisibility(0);
                userFolder.setIsDefault(0);
                userFolder.setLastUpdate(LocalDateTime.now());
                collectMapper.insertUserFolder(userFolder);
            }
            return userFolder;
        }catch (Exception e){
            logger.error(userId+" :用户获取默认收藏夹异常"+"原因: "+e);
            return null;
        }
    }

    // 获取用户收藏夹的分页数据
    public List<UserFolder> getUserFolders(Long userId, int offset, int size) {
        return  collectMapper.getUserFolders(userId,size,offset);
    }

    // 插入用户文件夹
    public long createUserFolder(UserFolder userFolder) {
        collectMapper.insertUserFolder(userFolder);
        return userFolder.getFolderId();
    }
    @Transactional
    public UserFolder  newUserFavorites(long userId,UserFolder needUserFolder){
        //根据userId 修改默认
        if(needUserFolder.getIsDefault()!=null){
            collectMapper.resetDefaultFolder(userId);
        }
        collectMapper.insertUserFolder(needUserFolder);
        return needUserFolder;
    }

    //判断文件夹中是否存在某一篇博客
   public boolean existsByFolderIdAndPostId(Long folderId, Long postId){
        return collectMapper.existsByFolderIdAndPostId(folderId, postId);
    }
    public int countPostsByFolderId(Long folderId){
        return collectMapper.countPostsByFolderId(folderId);
    }


   public void deletePostTagsByPostId(Long postId){
       postMapper.deletePostTagsByPostId(postId);
    }
   public void insertPostTag(Long postId, Long tagId){
       postMapper.insertPostTag(postId,tagId);
    }
    public int insertPost(Post post){
        return postMapper.insertPost(post);
    }
    public List<Long> getPostIdsWithTags(List<String> tagNames, Long offset, Long count) {
        return postMapper.selectPostIdsWithTagNames(tagNames, offset, count);
    }


    public boolean postExists(Long postId,Long userId, Integer postType) {
        int count = postMapper.countPostsByPostIdAndPostType(postId,userId, postType);
        return count > 0;  // 如果返回大于0，表示帖子存在
    }
    public Post getPostTitleAndContentById(Long postId, Long userId,Integer postType){
        return postMapper.getPostTitleAndContentById(postId,userId,postType);
    }

    public  Long getTagIdByName(String tagName){
       return postMapper.getTagIdByName(tagName);
    }


    // 根据 postId 查询帖子内容
    public String getContentByPostId(Long postId) {
        return postMapper.getContentByPostId(postId);
    }

  public List<BlogPostDetails> getRelevantRecommendations(List<String> keywords,List<String>tagNames){
        long limit=15;
        List<Long> getIdByKeyword =postMapper.selectPostIdsByKeywordsList(keywords);

        if(getIdByKeyword.size()<15){
            limit=15-getIdByKeyword.size();
        }
      // 使用 HashSet 来去重
      Set<Long> uniquePostIds = new HashSet<>(getIdByKeyword);
        long offset=0L;
        while (true) {
            List<Long> getIdByTagNane = postMapper.selectPostIdsWithTagNames(tagNames, offset, limit);
            if(getIdByTagNane.size()<limit){
                break;
            }
            boolean limited=false;
            // 对标签查询结果去重，加入到 uniquePostIds 中
            for (Long postId : getIdByTagNane) {
                if (!uniquePostIds.contains(postId)) {
                    limit--;
                    uniquePostIds.add(postId); // 只添加不重复的帖子 ID
                    if(limit==0){
                        limited=true;
                        break;
                    }
                }
            }
            if(limited){
                break;
            }
            offset=offset+getIdByTagNane.size();
        }
      List<BlogPostDetails> blogPostDetails = new ArrayList<>();

      for (Long postId : uniquePostIds) {
          BlogPostDetails postDetails = getBlogPostDetailsById(postId); // 根据 postId 查询帖子详情
          if (postDetails != null) {
              blogPostDetails.add(postDetails);  // 如果帖子详情不为空，加入结果列表
          }
      }
      return blogPostDetails;
  }

   public BlogPostDetails getBlogPostDetailsById(Long postId){
       //查询blogPostDetail
       BlogPostDetails blogPostDetail = advancedRedisService.queryWithHashPassThrough(
               RedisKeyPrefixConfig.BLOG_HASH_KEY_PREFIX,
               postId,
               BlogPostDetails.class,
               id -> postMapper.getBlogDetailApartContentById(id), // 使用 id 作为参数
               RedisKeyPrefixConfig.BLOG_HASH_KEY_EXPIRE,
               TimeUnit.MINUTES
       );

       //判断blogPostDetail是否为空
       if(blogPostDetail!=null){
           //查看blogPostDetail的内容是否为
           String content =blogPostDetail.getContent();
           if(content==null || content.trim().length()==0) {
               //根据查询数据库中content
               content= getContentByPostId(postId);
               if (content != null) {
                   blogPostDetail.setContent(content);
                   String lockKey = "lock:blog:content:" + postId;
                   RLock lock = redissonClient.getLock(lockKey);
                   try {
                       if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                           //异步处理redis写入content数据
                           String finalContent = content;
                           CompletableFuture.runAsync(() -> {
                               try {
                                   String hashKey=RedisKeyPrefixConfig.BLOG_HASH_KEY_PREFIX +postId;
                                   advancedRedisService.updateHashKeyValue(hashKey,"content", finalContent);
                                  // System.out.println("异步向 Redis 写入博客内容成功，博客ID: " + postId);
                               } catch (Exception e) {
                                   //System.err.println("向 Redis 写入博客内容失败，博客ID: " + postId);
                                   throw new RuntimeException(e.getMessage());
                               }
                           });
                       }
                   } catch (Exception e) {
                       logger.error("处理文件异常");
                       return null;
                   } finally {
                       lock.unlock();
                   }
               }else{
                   blogPostDetail.setContent("");
               }
           }
       }
       return blogPostDetail;
    }
    @Transactional
    public void updatePostTags(Long postId, List<String> newTagNames) {
        try {
            logger.info("更新"+postId+"的标签"+newTagNames);
            // 删除草稿与标签的所有关联
            deletePostTagsByPostId(postId);
            // logger.info("删除");
            // 插入新的草稿标签关联
            for (String tagName : newTagNames) {
                // 根据标签名查找 tag_id
                Long tagId = getTagIdByName(tagName);
                 //logger.info("查找"+tagId);
                if (tagId != null) {

                    // 如果找到了 tag_id，则插入关联
                   insertPostTag(postId, tagId);
                    // logger.info("插入");
                } else {
                    throw new RuntimeException("标签名 " + tagName + " 未找到，操作失败，事务已回滚");
                }
            }
        } catch (Exception e) {
            logger.error("更新标签出错了"+e.getMessage());
            // 如果出现异常，Spring 会自动回滚事务
            throw new RuntimeException("操作失败，事务已回滚", e);
        }
    }
    public  void updatePostContent(Long postId, String content){
       postMapper.updatePostContent(postId,content);
    }
    public void insertBlogPostDetails(BlogPostDetails blogPostDetails){
       postMapper.insertBlogPostDetails(blogPostDetails);
    }
    public List<BlogPostDetails> getBlogPostDetailsByStrPostIds(List<String> strPostIds) {
        List<BlogPostDetails> blogPostDetails = new ArrayList<>();
        for (String strId : strPostIds) {
            Long longId;
            try {
                longId = Long.parseLong(strId);
            } catch (Exception e) {
                longId = -1L;
            }
            if (!longId.equals(-1L)) {
                //开始查询数据
                BlogPostDetails blogPostDetail = advancedRedisService.queryWithHashPassThrough(
                        RedisKeyPrefixConfig.BLOG_HASH_KEY_PREFIX,
                        longId,
                        BlogPostDetails.class,
                        id -> postMapper.getBlogDetailApartContentById(id), // 使用 id 作为参数
                        RedisKeyPrefixConfig.BLOG_HASH_KEY_EXPIRE,
                        TimeUnit.MINUTES
                );
                if (blogPostDetail != null) {
                    blogPostDetails.add(blogPostDetail);
                }
            }
        }
        return blogPostDetails;
    }
    @Override
    public List<BlogPostDetails> getBlogPostDetails(Long userId, Long count,Long offset) {
        List<String> strPostIds = getRecommendedBlogsId(userId,count);
        System.out.println("推荐服务获取数据:"+strPostIds);
        if (strPostIds != null && !strPostIds.isEmpty()) {

            return getBlogPostDetailsByStrPostIds(strPostIds);
        }
        //逻辑推荐热点博客
        List<String> hotspot=getHotspotRange(offset,count);
        if(hotspot!=null&&!hotspot.isEmpty()){
            return getBlogPostDetailsByStrPostIds(hotspot);
        }
        //推荐热点博客信息
        return Collections.emptyList();
    }

    // 获取指定偏移量和数量的热点信息
    public List<String> getHotspotRange(long offset, long count) {
        // 使用 LRANGE 命令获取从 offset 开始，长度为 count 的子列表
        long end = offset + count - 1;  // 计算 stop 索引
        String key=RedisKeyPrefixConfig.BLOG_LIST_HOTSPOT_KEY;
        // 从 Redis 列表中获取对象类型数据
        List<Object> objectList = redisTemplate.opsForList().range(key, offset, end);

        // 如果需要，可以在这里将 Object 转换为实际的类型 MyObject
        return objectList.stream()
                .filter(item -> item instanceof String)
                .map(item -> (String) item)
                .collect(Collectors.toList());
    }

    private void setUserOffset(Long userId, Long offset) {
        String key = RedisKeyPrefixConfig.USER_HASH_INTEREST_OFFSET; // Hash 表的名称
        // 将用户 ID 和 offset 存储在 Hash 表中
        redisTemplate.opsForHash().put(key, userId.toString(), offset);
    }
    private Long getUserOffset(Long userId) {
        String key = RedisKeyPrefixConfig.USER_HASH_INTEREST_OFFSET; // Hash 表的名称
        // 从 Hash 表中获取指定用户的 offset
        Object offset = redisTemplate.opsForHash().get(key, userId.toString());
        return offset != null ? Long.valueOf(offset.toString()) : null; // 返回对应的 offset，若不存在则返回 null
    }
    private void setRemainingRecommendations(Long userId, Long remainingCount) {
        // 将未推荐的剩余数量存储到哈希中，键为 "user:recommendations"，字段为 userId，值为 remainingCount
        redisTemplate.opsForHash().put(RedisKeyPrefixConfig.USER_HASH_RECOMMENDATIONS, userId.toString(), remainingCount);
    }

    private Long getRemainingRecommendations(Long userId) {
        // 从 Hash 表中获取指定用户的 offset
        Object offset = redisTemplate.opsForHash().get(RedisKeyPrefixConfig.USER_HASH_RECOMMENDATIONS, userId.toString());
        return offset != null ? Long.valueOf(offset.toString()) : null; // 返回对应的 offset，若不存在则返回 null
    }
    private List<String> getInterestTagNames(Long userId) {
        String key = RedisKeyPrefixConfig.getUserInterestTagsKey(userId);
        // 从 Redis 中获取所有的标签信息
        Map<Object, Object> tagInfo = redisTemplate.opsForHash().entries(key);
        // 创建一个 List 用于存储符合条件的标签名称
        List<String> result = new ArrayList<>();
        // 遍历所有标签信息并筛选符合条件的标签
        for (Map.Entry<Object, Object> entry : tagInfo.entrySet()) {
            String tagName = (String) entry.getKey();
            Map<String, Object> tagDetails = (Map<String, Object>) entry.getValue();
            // 假设权重存储在 tagDetails 中的 "weight" 键下
            if (tagDetails.containsKey("weight")) {
                Integer weight = (Integer) tagDetails.get("weight");
                // 仅添加权重大于等于 5.jpg 的标签名称
                if (weight != null && weight >= 5) {
                    result.add(tagName);
                }
            }
        }
        return result; // 返回符合条件的标签名称列表
    }
    private static final String LOCK_KEY = "lock:create:recommendedBlog:list"; // 锁的键名
    private void addBolgIdsToRecommendedList(Long userId, Long offset, Long needCount) {
        if (offset != null && needCount != null && needCount > 0) {
            String lockKey = LOCK_KEY + userId;
            RLock lock = redissonClient.getLock(lockKey);
            int addedCount = 0;
            try {
                // 尝试获取锁，最多等待 10 秒，锁的持有时间为 30 秒
                if (lock.tryLock(10,30, TimeUnit.SECONDS)) {
                    while (true) {
                        List<String> tagNames = getInterestTagNames(userId);
                        long count = new Random().nextInt(5) + needCount;
                        // System.out.println(count);
                        List<Long> blogIds = getPostIdsWithTags(tagNames, offset+addedCount, count);
                        // System.out.println(blogIds);
                        // 数据库无更多数据
                        boolean haveMore = Long.parseLong(String.valueOf(blogIds.size())) == count;
                        String recommendedBlogKey = RedisKeyPrefixConfig.getUserRecommendedBlogKey(userId);
                        long currentTimeMillis = System.currentTimeMillis();
                        // 检查 ZSET 是否存在
                        if (Boolean.FALSE.equals(redisTemplate.hasKey(recommendedBlogKey))) {
                            // 如果 ZSET 不存在，直接添加所有 blogId
                            for (Long blogId : blogIds) {
                                redisTemplate.opsForZSet().add(recommendedBlogKey, blogId.toString(), currentTimeMillis);
                                addedCount++;
                            }
                        } else {
                            // ZSET 存在，逐个检查并添加
                            for (Long blogId : blogIds) {
                                if (redisTemplate.opsForZSet().score(recommendedBlogKey, blogId.toString()) == null) {
                                    redisTemplate.opsForZSet().add(recommendedBlogKey, blogId.toString(), currentTimeMillis);
                                    addedCount++;
                                }
                            }
                        }

                        // 设置当前已经查询所在的offset
                        setUserOffset(userId, haveMore ? offset + addedCount : -1);
                        // 剩余未被推荐的博客id
                        Long recommendations = getRemainingRecommendations(userId);
                        if (recommendations == null) {
                            recommendations = 0L;
                        }
                        setRemainingRecommendations(userId, recommendations + addedCount);
                        if (!haveMore || recommendations + addedCount >= needCount) {
                            break;
                        }
                    }
                }
            } catch (Exception e) {
                // 处理获取锁失败或其他异常
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }

    private List<String> getRecommendedBlogsId( Long userId, Long  count){
        System.out.println("进入:"+userId+"----"+count);
        if(count<=0){
            return Collections.emptyList();
        }
        //1.uid不存在 或者 uid存在但是redis没有记录用户感兴趣标签 或者 用户没有添加兴趣标签 ---->推送热点博客
        if (userId != null) {
            //2.redis记录的用户感兴趣标签
            String tagsKey = RedisKeyPrefixConfig.getUserInterestTagsKey(userId);
            logger.info("标签名"+tagsKey+Boolean.TRUE.equals(redisTemplate.hasKey(tagsKey)));
            if (Boolean.TRUE.equals(redisTemplate.hasKey(tagsKey))) {
                //3.设置推荐博客的键
                String recommendedBlogKey=RedisKeyPrefixConfig.getUserRecommendedBlogKey(userId);
                ZSetOperations<String, Object> zSetOperations = redisTemplate.opsForZSet();
                //4.获取当前用户兴趣标签分页查询所在的offset
                Long currOffset= getUserOffset(userId);
                if(currOffset==null){
                    //初始化
                    setUserOffset(userId,0L);
                    currOffset=0L;
                }
                //5.jpg.数据库还有数据可供查询 ----如果存放的是-1 则表示数据库无更多的推荐了
                boolean haveMore=currOffset!=-1L;
                if(Boolean.FALSE.equals(redisTemplate.hasKey(recommendedBlogKey))){
                    //5.jpg.推荐的博客列表不存在 空表并且数据库无数据查询
                    if(!haveMore) {
                        return Collections.emptyList();
                    }
                    //6.添加
                    addBolgIdsToRecommendedList(userId,currOffset,count);
                    haveMore=false;
                }
                Long recommendations=getRemainingRecommendations(userId);
                if( recommendations==null){
                    recommendations=0L;
                    setRemainingRecommendations(userId,recommendations);
                }else{
                    //推荐表存在 haveMore数据库有数据 但是未推荐的数量小于count
                    if(haveMore && recommendations<count){
                        addBolgIdsToRecommendedList(userId,currOffset,count);
                        //修改剩余推荐的数据
                        Long tepRecommendations=getRemainingRecommendations(userId);
                        recommendations=tepRecommendations!=null?tepRecommendations:0;
                    }
                }
                if(recommendations==0){
                    return Collections.emptyList();
                }
                // 将 recommendations 转换为负数
                long start= -Math.abs(recommendations);
                //System.out.println(start);
                long end=start+count-1;
                if(recommendations<=count){
                    end=-1L;
                    setRemainingRecommendations(userId,0L);
                }else{
                    setRemainingRecommendations(userId,recommendations-count);
                }
                //除去了其他情况
                Set<Object> recommendedBlogIds = zSetOperations.range(recommendedBlogKey,start,end);
                return recommendedBlogIds != null
                        ? recommendedBlogIds.stream().map(String::valueOf).collect(Collectors.toList())
                        : Collections.emptyList();
            }//可以从redis获取用户感兴趣标签
        }
        return Collections.emptyList();
    }

}